﻿// Decompiled with JetBrains decompiler
// Type: MCM.LightInject.AssemblyScanner
// Assembly: MCMv5, Version=5.10.2.0, Culture=neutral, PublicKeyToken=null
// MVID: 7AB326B9-B2B4-41C2-9177-68E944071101
// Assembly location: D:\steam\steamapps\workshop\content\261550\2859238197\bin\Win64_Shipping_Client\MCMv5.dll

using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reflection;

#nullable disable
namespace MCM.LightInject
{
  [ExcludeFromCodeCoverage]
  internal class AssemblyScanner : IAssemblyScanner
  {
    private readonly ITypeExtractor concreteTypeExtractor;
    private readonly ITypeExtractor compositionRootTypeExtractor;
    private readonly ICompositionRootExecutor compositionRootExecutor;
    private readonly IGenericArgumentMapper genericArgumentMapper;
    private Assembly currentAssembly;

    public AssemblyScanner(
      ITypeExtractor concreteTypeExtractor,
      ITypeExtractor compositionRootTypeExtractor,
      ICompositionRootExecutor compositionRootExecutor,
      IGenericArgumentMapper genericArgumentMapper)
    {
      this.concreteTypeExtractor = concreteTypeExtractor;
      this.compositionRootTypeExtractor = compositionRootTypeExtractor;
      this.compositionRootExecutor = compositionRootExecutor;
      this.genericArgumentMapper = genericArgumentMapper;
    }

    public void Scan(
      Assembly assembly,
      IServiceRegistry serviceRegistry,
      Func<ILifetime> lifetimeFactory,
      Func<Type, Type, bool> shouldRegister,
      Func<Type, Type, string> serviceNameProvider)
    {
      foreach (Type concreteType in this.GetConcreteTypes(assembly))
        this.BuildImplementationMap(concreteType, serviceRegistry, lifetimeFactory, shouldRegister, serviceNameProvider);
    }

    public void Scan(Assembly assembly, IServiceRegistry serviceRegistry)
    {
      Type[] compositionRootTypes = this.GetCompositionRootTypes(assembly);
      if (compositionRootTypes.Length == 0 || object.Equals((object) this.currentAssembly, (object) assembly))
        return;
      this.currentAssembly = assembly;
      this.ExecuteCompositionRoots((IEnumerable<Type>) compositionRootTypes);
    }

    private static IEnumerable<Type> GetBaseTypes(Type concreteType)
    {
      for (Type baseType = concreteType; baseType != typeof (object) && baseType != (Type) null; baseType = baseType.GetTypeInfo().BaseType)
        yield return baseType;
    }

    private void ExecuteCompositionRoots(IEnumerable<Type> compositionRoots)
    {
      foreach (Type compositionRoot in compositionRoots)
        this.compositionRootExecutor.Execute(compositionRoot);
    }

    private Type[] GetConcreteTypes(Assembly assembly)
    {
      return this.concreteTypeExtractor.Execute(assembly);
    }

    private Type[] GetCompositionRootTypes(Assembly assembly)
    {
      return this.compositionRootTypeExtractor.Execute(assembly);
    }

    private void BuildImplementationMap(
      Type implementingType,
      IServiceRegistry serviceRegistry,
      Func<ILifetime> lifetimeFactory,
      Func<Type, Type, bool> shouldRegister,
      Func<Type, Type, string> serviceNameProvider)
    {
      foreach (Type serviceType in implementingType.GetTypeInfo().ImplementedInterfaces.ToArray<Type>())
      {
        if (shouldRegister(serviceType, implementingType))
          this.RegisterInternal(serviceType, implementingType, serviceRegistry, lifetimeFactory(), serviceNameProvider);
      }
      foreach (Type baseType in AssemblyScanner.GetBaseTypes(implementingType))
      {
        if (shouldRegister(baseType, implementingType))
          this.RegisterInternal(baseType, implementingType, serviceRegistry, lifetimeFactory(), serviceNameProvider);
      }
    }

    private void RegisterInternal(
      Type serviceType,
      Type implementingType,
      IServiceRegistry serviceRegistry,
      ILifetime lifetime,
      Func<Type, Type, string> serviceNameProvider)
    {
      TypeInfo typeInfo = serviceType.GetTypeInfo();
      if (implementingType.GetTypeInfo().ContainsGenericParameters && !this.genericArgumentMapper.Map(serviceType, implementingType).IsValid)
        return;
      if (typeInfo.IsGenericType && typeInfo.ContainsGenericParameters)
        serviceType = typeInfo.GetGenericTypeDefinition();
      serviceRegistry.Register(serviceType, implementingType, serviceNameProvider(serviceType, implementingType), lifetime);
    }
  }
}
